<script setup lang="ts">
import { onMounted } from 'vue'
import { Peer } from 'peerjs'

const _window: any = window

const init = () => {
  const peer = new Peer(
    '' +
      Math.floor(Math.random() * 2 ** 18)
        .toString(36)
        .padStart(4, '0'),
    {
      host: location.hostname,
      port: 10000,
      debug: 1,
      path: '/rtc'
    }
  )

  _window.peer = peer

  const callBtn: any = document.querySelector('.call-btn')
  const videoContainer: any = document.querySelector('.call-container')
  const hangUpBtn: any = document.querySelector('.hangup-btn')

  let conn
  let code

  /**
   * FUNCTIONS
   */

  /**
   * Gets connection code/peer id from caller
   * @returns {string} - the code retrieved
   */
  function getStreamCode() {
    code = _window.prompt('输入要连接的设备ID')
    return code
  }

  /**
   * Gets the local video stream of the current caller
   * @param callbacks - an object to set the success/error behaviour
   * @returns {void}
   */

  async function getLocalStream() {
    if (!window.isSecureContext) return (_window.localStream = new MediaStream())

    if (_window.localStream) return _window.localStream

    const displayMediaOptions: any = {
      video: {
        displaySurface: 'browser'
      },
      audio: {
        suppressLocalAudioPlayback: false
      }
    }

    const captureStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions)

    setLocalStream(captureStream)

    return captureStream
  }

  /**
   * Sets the src of the HTML element on the page to the local stream
   * @param stream
   * @returns {void}
   */

  function setLocalStream(stream) {
    _window.localVideo.srcObject = stream
    _window.localVideo.autoplay = true
    _window.localStream = stream
  }

  /**
   * Sets the src of the HTML element on the page to the remote stream
   * @param stream
   * @returns {void}
   */
  function setRemoteStream(stream) {
    _window.remoteVideo.srcObject = stream
    _window.remoteVideo.autoplay = true
    _window.peerStream = stream
  }

  /**
   * Displays the video controls and correct copy
   * @returns{void}
   */
  function showConnectedContent() {
    _window.caststatus.textContent = `已连接`
    callBtn.hidden = true
    videoContainer.hidden = false
  }

  /**
   * Displays the call button and peer ID
   * @returns{void}
   */
  function showCallContent() {
    _window.caststatus.textContent = `你的设备ID: ${peer.id}`
    callBtn.hidden = false
    videoContainer.hidden = true
  }

  /**
   * Connect the peers
   * @returns {void}
   */

  function connectPeers() {
    conn = peer.connect(code)
  }

  /**
   * EVENTS
   */

  /**
   * Get the connection code, connect peers and create a call
   */
  callBtn.addEventListener('click', function () {
    getStreamCode()
    connectPeers()

    if (code)
      getLocalStream().then((res) => {
        const call = peer.call(code, _window.localStream)
        /**
         * when the call is streaming, set the remote stream for the caller
         */
        call.on('stream', function (stream) {
          setRemoteStream(stream)
          showConnectedContent()
        })
      })
  })

  /**
   * Close the connection between peers
   */
  hangUpBtn.addEventListener('click', function () {
    conn.close()
    showCallContent()
  })

  /**
   * When the peer has connected to the server, diplay the peer ID
   */
  peer.on('open', function () {
    _window.caststatus.textContent = `你的设备ID: ${peer.id}`
  })

  /**
   * When a data connection between peers is open, get the connecting peer's details
   */
  peer.on('connection', function (connection) {
    conn = connection
  })

  /**
   * When a call has been created, answer it and set the remote stream for the person being called
   */
  peer.on('call', function (call) {
    // 页面没获取焦点不会有弹框

    getLocalStream().then((res) => {
      call.answer(_window.localStream)
    })
    showConnectedContent()
    call.on('stream', function (stream) {
      setRemoteStream(stream)
    })
    conn.on('close', function () {
      showCallContent()
    })
  })

  /**
   * Log errors to the console when they occur
   */
  peer.on('error', (err) => console.error(err))
}

onMounted(() => {
  init()
})
</script>

<template>
  <div>
    <div class="container">
      <h2>通信</h2>
      <p id="caststatus" class="big">连接中...</p>
      <button class="call-btn">呼叫</button>
      <section class="call-container" hidden>
        <div class="video-container">
          <h3>远程</h3>
          <video id="remoteVideo" controls muted="true"></video>
          <h3>本地</h3>
          <video id="localVideo" controls muted="true"></video>
        </div>
        <button class="hangup-btn">挂断</button>
      </section>
    </div>
  </div>
</template>

<style scoped></style>
